1. Introduction

It is often hard to estimate the effect of international aid. It is particularly challenging regarding military aid, where data is rarely available. This difficulty is particularly pressing in Ukraine, where continued military support is central to the country’s defense against Russian aggression. As U.S. assistance appears increasingly uncertain, European allies must assess whether aid contributions make a meaningful difference to ensure the efficient use of limited resources. The lack of available data on delivered weapons is a primary obstacle to evaluating aid’s effectiveness. We address this challenge by testing whether international military aid can serve as a proxy for delivered weapons.

2. Evaluating Military Aid

This project contributes to two strands of literature: the effectiveness of international aid and the role of military assistance in shaping security outcomes. Glanville and Pattison (2024) highlight the significant opportunity costs associated with military support, emphasizing how it can divert resources and political attention from pressing global challenges such as poverty, public health, and climate change. These concerns underscore the need to critically assess whether military aid is indeed achieving its intended goal in effectively contributing to Ukraine self self-defence, so that its trade-offs can be properly justified. Complementing this, Tian et al. (2023) document a sharp rise in global defense spending following Russia’s invasion, especially among countries geographically or strategically close to the conflict. This shift raises important questions about the effectiveness of aid not only in contributing to Ukraine’s security and enhancing regional stability. Evaluating the real impact of military assistance is therefore essential for informing future policy decisions and international cooperation.

3. Data Sourcers

In this project, we explore whether novel data sources allow us to detect such effects in the context of Ukraine. Since granular, public data on actual weapons deliveries is unavailable, we rely on (1) open-source data on allocated military aid from the Ukraine Support Tracker (UST) (Trebesch et. al, 2023), and (2) satellite-based fire detection data, processed by The Economist and Sondre Ulvund Solstad (The Economist, 2022), to indicate battlefield activity.

The UST collects open-source data on official, bilateral aid from international allies to Ukraine. They track allocations according to donors and according to the type of aid: military aid includes weapons, ammunition, military equipment, and funds for procuring weapons or ammunition. The dataset contains 3737 allocations or commitments of aid to Ukraine by 41 countries and three international institutions from January 2022 to January 2025. An ’allocation’ refers to an official act at the administrative level of government, such as a ministerial budget.

Crucially, the UST does not report aid delivered to Ukraine. It is limited to reporting donor-side allocations, which ostensibly represent a measure of political support. It is uncertain whether allocated aid is in fact delivered, in what form it is realized, and how long it can take for it to be used on the battlefront. Therefore, we expect that using military aid as a proxy for delivered weapons to Ukraine is subject to significant measurement error. However, there may still be some relation between military aid and war outcomes. Since international military aid is allocated, after a certain lag, some of it would be realized as weapons that are then transported to the front line and used to affect the outcomes of the war.

The War Fires Database uses satellite images of fires in Ukraine and identifies them as being war-related or not. It identifies fire incidents likely caused by military activity in Ukraine by comparing observed fire patterns to historical baselines. By filtering out natural wildfires and leveraging spatial, temporal, and contextual data (e.g., population density and proximity to conflict zones), the model assigns probabilities to classify fires as war-related. The data also captures the length of the fire area and measures it over time. The area affected by sustained fires helps to distinguish between temporary fires and persistent burning that is more likely to be war-related. This helps filter out short-lived fires and focuses on those that indicate ongoing military activity, such as artillery shelling or airstrikes.

Therefore, this database provides a proxy for war outcomes by tracking the spread and frequency of conflict-driven destruction. Unlike traditional battlefield reports, which may be delayed, biased, or incomplete, this dataset offers a real-time, physical manifestation of military engagements, making it a more objective and continuous measure of conflict dynamics. The map below presents the incidence and size of war-related fires in Ukraine over time. Before we proceed to our tests, we must first clean the data sets and aggregate them on the time variable to produce two continuous series of international military aid and war fires over time.

sf_fires <- st_as_sf(ukraine_fires, coords = c("LONGITUDE", "LATITUDE"), crs = 4326)

ggplot(sf_fires) +
  geom_sf(aes(size = length_of_war_fire_area), alpha = 0.9, color = "red3") +
  facet_wrap(~year) +
  theme_minimal() +
  theme(
    legend.position = "none",
    plot.title = element_text(size = 18, hjust = 0.5, face = "bold"),
    plot.subtitle = element_text(size = 14, hjust = 0.5)
  ) +
  labs(
    title = "Annual War Fires in Ukraine",
    subtitle = "Dot size reflects fire intensity"
  ) +
  scale_size_continuous(range = c(0.000001, 0.05))

Aggregate UST Data on Announcement Date

# Aggregate data by announcement_date and item_type
UST_aid_type_general <- UST_allocations %>%
  group_by(announcement_date, aid_type_general) %>%
  summarise(
    total_item_numb = sum(item_numb, na.rm = TRUE),  # Sum total items
    total_value_EUR = sum(tot_sub_activity_value_EUR_redistr, na.rm = TRUE)  # Sum total value
  ) %>%
  ungroup()

Aggregate War Fires Data on Incidence Date

# Aggregate war_fire and length_of_war_fire_area on date
war_fires_aggregated <- ukraine_fires %>%
  group_by(date) %>%
  summarise(
    total_war_fires = sum(war_fire, na.rm = TRUE),  # Sum war fires per day
    total_war_fire_area = sum(length_of_war_fire_area, na.rm = TRUE),  # Sum war fire area per day
    .groups = "drop"
  )

glimpse(war_fires_aggregated)
## Rows: 808
## Columns: 3
## $ date                <date> 2022-02-24, 2022-02-25, 2022-02-26, 2022-02-27, 2…
## $ total_war_fires     <dbl> 30, 1, 19, 9, 7, 1, 1, 2, 3, 5, 26, 3, 14, 65, 57,…
## $ total_war_fire_area <dbl> 31381, 1046, 19874, 9374, 7215, 1041, 1041, 2082, …

4. Empirical Strategy

In the following sections we apply four tests with the purpose of evaluating whether the relation between international military aid and war fires behaves as we would expect the relation between delivered weapons and battleground activity to behave. If the results of these tests confirm our expectations, then we will have increased confidence that allocated military aid can be used as a proxy for delivered weapons.

As a proxy for delivered weapons, we will use the cumulative value of allocations of military aid. We use the value of aid in euros (EUR) because the number and type of weapons is not often reported by donors. Moreover, we take the cumulative value because weapons can be used over a long period, so weapons delivered at the beginning of the conflict have become a part of Ukraine’s stock and are likely still being used actively. Finally, we will use 7 months as a general estimate for aid to be realized as weapons and equipment on the ground. Determining the time it takes for military aid to reach and impact operations is complex, as it varies based on the type of equipment, the donor country, and logistical considerations. Journalistic sources claim delivery times can range from two months to a year, depending on the specific circumstances surrounding each aid package (The Times, 2024). Given these variations, we use 7 months as a midpoint estimate, aiming to capture the reported periods taken to procure and deliver weapons to Ukraine.

If allocated aid can be a proxy for delivered weapons, we expect to see measurable correlations between cumulative aid and the intensity of fire-related activity. We further hypothesize that these effects should be more visible in Russian-controlled areas, where donated weapons are more likely to be deployed offensively, and in better-connected regions, where transport infrastructure allows for faster redistribution of aid. Finally, donated weapons used in Russian-controlled territories will likely avoid harming valuable natural resources that Ukraine expects to recover. Therefore, we expect to see a negative correlation between international military aid and proximity to natural resources in Russian-controlled territories.

If each of these four tests fulfills our expectations, then we have increased confidence that the relationship between international military aid and war fires captures the effect of delivered weapons and can thus be used to evaluate its efficiency.

4.1 First test: Simple Correlation

We begin by exploring whether there is some simple correlation between the entire series of cumulative military aid and the size of war-related fires. Below we visualize both series over time This plot suggests that there can be some relation between the two. Following, we perform a Pearson correlation test to assess whether there is a statistically significant linear association between these two variables. The results show a positive and statistically significant correlation between cumulative military aid and war fire area, with a Pearson correlation coefficient of 0.2925. This indicates a moderate positive relationship—as military aid indicates, the extent of war-related fires also tends to increase. The low p-value (5.893e-12) confirms that this relationship is highly statistically significant, meaning it’s unlikely to be due to random chance.

# Compute cumulative sum for both variables
aid_war_fires_cumulative <- aid_war_fires_merged %>%
  arrange(announcement_date) %>%
  mutate(
    cumulative_military_aid = cumsum(total_value_EUR),
    cumulative_war_fire_area = cumsum(total_war_fire_area),
    scaled_war_fire_area = (cumulative_war_fire_area - min(cumulative_war_fire_area)) /
      (max(cumulative_war_fire_area) - min(cumulative_war_fire_area))
  )


# Plot cumulative trends over time
ggplot(aid_war_fires_cumulative, aes(x = announcement_date)) +
  geom_line(aes(y = cumulative_military_aid, color = "Cumulative Military Aid (EUR)"), size = 1.2) +
  geom_line(aes(y = scaled_war_fire_area * max(cumulative_military_aid), color = "War Fire Area (Scaled)"), size = 1.2) +
  scale_y_continuous(
    name = "Cumulative Military Aid (EUR)",
    labels = label_number(scale = 1e-9, suffix = "B"),
    sec.axis = sec_axis(
      trans = ~ . / max(aid_war_fires_cumulative$cumulative_military_aid),
      name = "War Fire Area (Scaled 0–1)"
    )
  ) +
  labs(
    title = "Cumulative Military Aid and War Fire Area",
    x = "Date",
    y = "Cumulative Military Aid (EUR)"
  ) +
  scale_color_manual(
    values = c("Cumulative Military Aid (EUR)" = "blue3", "War Fire Area (Scaled)" = "red3")
  ) +
  theme_minimal() +
  theme(
    legend.position = "bottom",
    legend.title = element_blank(),
    plot.title = element_text(size = 18, hjust = 0.5, face = "bold")
  )

# Ensure data is sorted correctly
aid_war_fires_cumulative <- aid_war_fires_merged %>%
  arrange(announcement_date) %>%
  mutate(
    cumulative_military_aid = cumsum(total_value_EUR),  # Only Aid is cumulative
    total_war_fire_area = total_war_fire_area  # Keep fire area as is
  )

# Compute correlation
correlation_result <- cor.test(
  aid_war_fires_cumulative$cumulative_military_aid,
  aid_war_fires_cumulative$total_war_fire_area,
  method = "pearson"
)

# Print correlation results
print(correlation_result)
## 
##  Pearson's product-moment correlation
## 
## data:  aid_war_fires_cumulative$cumulative_military_aid and aid_war_fires_cumulative$total_war_fire_area
## t = 7.0423, df = 530, p-value = 5.893e-12
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.2128001 0.3683685
## sample estimates:
##       cor 
## 0.2925186
# Extract key values
correlation_value <- correlation_result$estimate
p_value <- correlation_result$p.value

# Print formatted output
cat("\n Correlation between Cumulative Military Aid and Total War Fire Area:\n")
## 
##  Correlation between Cumulative Military Aid and Total War Fire Area:
cat("Pearson Correlation: ", round(correlation_value, 4), "\n")
## Pearson Correlation:  0.2925
cat("p-value: ", format.pval(p_value, digits = 4), "\n")
## p-value:  5.893e-12
# Save results
cor_results_df <- data.frame(
  correlation = correlation_value,
  p_value = p_value
)

4.2 Second Test: Area Under Control

Following, we will test the correlation according to which side controlled the area in which a war fire incidence was recorded. We incorporate data on who controlled which areas during 2024, and identify fires occurring in Russian-controlled areas. The correlation between these and military aid to Ukraine should be higher, since it better captures Ukraine’s offensive capacity than fires occurring overall.

First, we incorporate spatial data on areas under Russian control from the Institute for the Study of War (ISW) (Harward, 2025). Following, we join the Russian controlled areas in 2024 with war fires in 2024 by location and date to identify war fires occurring in Russian-controlled areas and fires in Ukrainian-controlled areas. For that, we must filter the both datasets for their values in 2024, join them and identify fires located in a Russian-controlled area and those in a Ukrainian-controlled area. Finally, we compute the correlation between cumulative aid and war fire size and visualize it for each region.

War Fires in Russian & Ukrainian Controlled Areas

# Remove empty geometries from Russian-controlled areas
russian_control_2024 <- russian_control %>%
  filter(year == "2024") %>%
  filter(!st_is_empty(geometry)) %>%
  select(year, geometry, data_name)

# Select relevant columns for war fires and retain "date"
war_fires_2024 <- sf_fires %>%
  filter(year == 2024) %>%
  select(year, geometry, date, length_of_war_fire_area)  # Retaining date for correlation analysis

Join War Fires with Areas Under Different Control

# Perform the Spatial Join to add Russian-controlled areas to each fire point, without cutting geometries:
fires_by_area <- st_join(war_fires_2024, russian_control_2024, left = TRUE)

# Now, we create an in_russian_controlled Columnn with value 1 if a fire has matched a Russian-controlled area, and 0 otherwise since it’s in Ukrainian-controlled territory. 
fires_by_area <- fires_by_area %>%
  mutate(in_russian_controlled = ifelse(!is.na(data_name), 1, 0))
# Load Ukraine shapefile (adjust path as needed)
ukraine_map <- st_read("gadm41_UKR_shp/gadm41_UKR_2.shp")
## Reading layer `gadm41_UKR_2' from data source 
##   `C:\Users\Camilo Giraldo\Desktop\BSE - ITFD\2nd Term\Geospatial data science and economic spatial models\Final project\Final\gadm41_UKR_shp\gadm41_UKR_2.shp' 
##   using driver `ESRI Shapefile'
## Simple feature collection with 629 features and 13 fields
## Geometry type: MULTIPOLYGON
## Dimension:     XY
## Bounding box:  xmin: 22.14045 ymin: 44.38597 xmax: 40.21807 ymax: 52.37503
## Geodetic CRS:  WGS 84
ukraine_map <- st_transform(ukraine_map, crs = 4326)

# Plot the map
ggplot() +
  # Base Ukraine map
  geom_sf(data = ukraine_map, fill = "gray90", color = "black") +
  
  # Russian-controlled areas
  geom_sf(data = russian_control_2024, fill = "gray25", color = "gray25", alpha = 0.5) +
  
  # War fires in Russian-controlled areas (blue)
  geom_sf(data = fires_by_area %>% filter(in_russian_controlled == 1), 
          aes(size = length_of_war_fire_area), 
          alpha = 0.4,
          color = "blue3") +
  
  # War fires in Ukrainian-controlled areas (red)
  geom_sf(data = fires_by_area %>% filter(in_russian_controlled == 0), 
          aes(size = length_of_war_fire_area), 
          alpha = 0.4,
          color = "red3") +
  
  # Labels & formatting
  theme_minimal() +
  theme(
    legend.position = "none",
    plot.title = element_text(size = 18, hjust = 0.5, face = "bold"),
    plot.subtitle = element_text(size = 14, hjust = 0.5)
  ) +
  labs(
    title = "War Fires by Control in Ukraine (2024)",
    subtitle = "Blue = Russian-Controlled | Red = Ukrainian-Controlled | Dot size = fire area",
    caption = "Source: ISW & Economist Fire Data"
  ) +
  scale_size_continuous(range = c(0.000001, 0.05))

Scatter plots of cumulative military aid and the size of war fires by area of control.

# Combine datasets and add control_status variable
aid_fires_combined <- bind_rows(
  aid_war_fires_russian %>% mutate(control_status = "Russian-Controlled"),
  aid_war_fires_ukrainian %>% mutate(control_status = "Ukrainian-Controlled")
)

# Compute correlation labels per region
cor_labels <- aid_fires_combined %>%
  group_by(control_status) %>%
  summarize(
    r = round(cor(total_war_fire_area, cumulative_military_aid, use = "complete.obs"), 3),
    x = min(total_war_fire_area, na.rm = TRUE),
    y = max(cumulative_military_aid, na.rm = TRUE),
    .groups = "drop"
  ) %>%
  mutate(label = paste0("r = ", r))

# Faceted scatter plot
ggplot(aid_fires_combined, aes(x = total_war_fire_area, y = cumulative_military_aid)) +
  geom_point(aes(color = control_status), alpha = 0.6) +
  geom_smooth(method = "lm", se = FALSE, aes(color = control_status), linetype = "dashed") +
  geom_text(
    data = cor_labels,
    aes(x = x, y = y, label = label, color = control_status),
    hjust = 0, size = 5, inherit.aes = FALSE
  ) +
  facet_wrap(~ control_status) +
  scale_y_continuous(labels = comma) +
  scale_x_continuous(labels = comma) +
  scale_color_manual(
    values = c("Russian-Controlled" = "blue3", "Ukrainian-Controlled" = "red3")
  ) +
  labs(
    title = "Correlation Between War Fires and Military Aid by Region",
    subtitle = "Comparison of Russian- and Ukrainian-Controlled Areas",
    x = "Total War Fire Area",
    y = "Cumulative Military Aid (EUR)",
    caption = "Source: ISW & Aid Data"
  ) +
  theme_minimal() +
  theme(
    legend.position = "none",
    plot.title = element_text(size = 18, hjust = 0.5, face = "bold"),
    plot.subtitle = element_text(size = 13, hjust = 0.5, face = "bold"),
    strip.text = element_text(size = 12, face = "bold"),
    panel.spacing = unit(2, "lines")
  )
## `geom_smooth()` using formula = 'y ~ x'

4.3 Third Test: Distance to Roads

This section investigates whether better road connectivity strengthens the observed relationship between cumulative military aid and fire incidents in Ukraine. We hypothesize that regions with better access to primary road networks may show a stronger positive association between cumulative military aid and conflict activity, as aid-supported operations depend on effective logistics and transportation.

Using spatial data from the World Bank (2023), we map Ukraine’s primary road infrastructure—focusing on major transportation arteries most relevant to large-scale military logistics. Next, we compute the Euclidean distance from each located fire event to the nearest primary road using spatial distance matrices. This allows us to use proximity to roads as a proxy for accessibility.

ukraine_roads <- st_read("hotosm_ukr_roads_lines_shp/hotosm_ukr_roads_lines.shp")
## Reading layer `hotosm_ukr_roads_lines' from data source 
##   `C:\Users\Camilo Giraldo\Desktop\BSE - ITFD\2nd Term\Geospatial data science and economic spatial models\Final project\Final\hotosm_ukr_roads_lines_shp\hotosm_ukr_roads_lines.shp' 
##   using driver `ESRI Shapefile'
## Simple feature collection with 2108459 features and 14 fields
## Geometry type: MULTILINESTRING
## Dimension:     XY
## Bounding box:  xmin: 22.11972 ymin: 44.38709 xmax: 40.22252 ymax: 52.39792
## Geodetic CRS:  WGS 84
ukraine_roads <- st_transform(ukraine_roads, crs = 4326)

roads_primary <- ukraine_roads %>%
  filter(highway %in% c("primary"))

# Define Kyiv coordinates (city center)
kyiv_sf <- st_as_sf(data.frame(
  name = "Kyiv",
  lon = 30.5234,
  lat = 50.4501
), coords = c("lon", "lat"), crs = st_crs(ukraine_map))

# Plot roads and Kyiv
ggplot() +
  geom_sf(data = ukraine_map, fill = "grey90", color = "black") +
  geom_sf(data = roads_primary, color = "darkred", size = 0.5) +
  geom_sf(data = kyiv_sf, aes(shape = name), color = "blue", size = 4) +
  scale_shape_manual(name = NULL, values = c("Kyiv" = 16)) +
  labs(
    title = "Major Road Network and Location of Kyiv",
    caption = "Source: World Bank Road Data & GADM Ukraine"
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(size = 16, hjust = 0.5, face = "bold"),
    legend.position = "bottom"
  )

Fire Incidence by Road Proximity

To explore the relationship between fire activity and road proximity, we categorize fires into distance bins based on their nearness to primary roads. The resulting distribution shows that a significant number of fire incidents occur within 1 kilometer of a primary road, suggesting these routes may be strategic targets in the conflict. This pattern could reflect efforts to disrupt enemy logistics or may simply indicate that conflict activity is concentrated in more accessible regions.

dist_matrix <- st_distance(fires_aggregated_lagged, roads_primary)
# Add minimum distance to fire data
fires_aggregated_lagged$min_dist_to_road_km <- apply(dist_matrix, 1, min) / 1000  # in km

# Create distance bins and aggregate
fires_aggregated_lagged <- fires_aggregated_lagged %>%
  mutate(distance_bin = cut(min_dist_to_road_km, 
                            breaks = c(0, 1, 5, 10, 15, 20, 50, Inf), 
                            labels = c("<1km", "1–5km", "5–10km", "10–15km", "15–20km", "20–50km", ">50km"),
                            include.lowest = TRUE))

fire_incidence_by_distance <- fires_aggregated_lagged %>%
  group_by(distance_bin) %>%
  summarize(fire_count = n()) %>%
  ungroup()

# Plot
ggplot(fire_incidence_by_distance, aes(x = distance_bin, y = fire_count)) +
  geom_bar(stat = "identity", fill = "firebrick", alpha = 0.8, width = 0.7) +
  geom_text(aes(label = fire_count), vjust = -0.5, size = 4, fontface = "bold") +  # Add labels
  labs(
    title = "Distribution of War Fires by Distance to Primary Roads",
    subtitle = "Most fire incidents occur within 5km of road infrastructure",
    x = "Distance to Nearest Road (km)",
    y = "Number of War Fire Events"
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(size = 16, hjust = 0.5, face = "bold"),
    plot.subtitle = element_text(size = 12, hjust = 0.5, face = "bold"),
    axis.text.x = element_text(angle = 0, vjust = 0.5, size = 11),
    panel.grid.minor = element_blank()
  )

Fire-Aid Correlation

In regions with better access to road infrastructure, military aid may more directly support logistics and operational capabilities, potentially intensifying conflict activity, and thus, increasing the incidence of fires. To explore this, we first merge the fire dataset—containing the distance from each fire to the nearest road—with military aid data based on the date of aid announcement. We then calculate, for each day and region under territorial control (Ukrainian or Russian), the average distance of fires to the nearest road, as a proxy for accessibility, the daily total value of military aid received and the cumulative value of aid over time, to reflect how the buildup of resources may affect conflict dynamics.

#Merge distance with aid information
dist_road_corr <- fires_aggregated_lagged %>%
  left_join(UST_aid_type_general, by = "announcement_date") %>%
  filter(!is.na(min_dist_to_road_km) & !is.na(total_value_EUR))

# Aggregate daily average distance and cumulative aid per region
dist_daily_combined <- dist_road_corr %>%
  group_by(control_status, announcement_date) %>%
  summarize(
    avg_distance_km = mean(min_dist_to_road_km, na.rm = TRUE),
    daily_aid = sum(total_value_EUR, na.rm = TRUE)
  ) %>%
  arrange(control_status, announcement_date) %>%
  group_by(control_status) %>%
  mutate(cumulative_aid = cumsum(daily_aid)) %>%
  ungroup()


# Combine both groups
dist_combined <- dist_daily_combined %>%
  filter(control_status %in% c("Russian-Controlled", "Ukrainian-Controlled"))

# Calculate correlation labels per region
cor_labels <- dist_combined %>%
  group_by(control_status) %>%
  summarize(
    r = round(cor(avg_distance_km, cumulative_aid, use = "complete.obs"), 3),
    x = min(avg_distance_km, na.rm = TRUE),
    y = max(cumulative_aid, na.rm = TRUE),
    .groups = "drop"
  ) %>%
  mutate(label = paste0("r = ", r))

# Faceted plot with correlation labels
ggplot(dist_combined, aes(x = avg_distance_km, y = cumulative_aid)) +
  geom_point(aes(color = control_status), alpha = 0.6) +
  geom_smooth(method = "lm", se = FALSE, aes(color = control_status), linetype = "dashed") +
  geom_text(
    data = cor_labels,
    aes(x = x, y = y, label = label, color = control_status),
    hjust = 0, size = 5, inherit.aes = FALSE
  ) +
  facet_wrap(~ control_status) +
  scale_y_continuous(labels = comma) +
  labs(
    title = "Avg. Distance to Roads vs. Cumulative Military Aid by Region",
    subtitle = "Comparison of Russian- and Ukrainian-Controlled Areas",
    x = "Average Distance to Nearest Road (km)",
    y = "Cumulative Military Aid (EUR)",
    caption = "Source: ISW & Aid Data"
  ) +
  scale_color_manual(
    values = c("Russian-Controlled" = "blue3", "Ukrainian-Controlled" = "red3")
  ) +
  theme_minimal() +
  theme(
    legend.position = "none",
    plot.title = element_text(size = 18, hjust = 0.5, face = "bold"),
    plot.subtitle = element_text(size = 13, hjust = 0.5, face = "bold"),
    strip.text = element_text(size = 12, face = "bold"),
    panel.spacing = unit(2, "lines")
  )

Results suggest a negative correlation between aid volume and fire distance from roads, implying that military aid may intensify conflict activity particularly in accessible regions. This supports the idea that aid is more effectively deployed in logistically connected areas, leading to observable increases in fire incidents where transport infrastructure facilitates weapon distribution and operations.

4.4. Fourth test: Natural Resources

In this section, we visualize the spatial distribution of strategic mineral deposits across Ukraine using geospatial data from the USGS Mineral Resources Data System (MRDS). The map below filters the mineral sites to include only those within Ukraine’s administrative boundaries. Each deposit is categorized into key mineral groups (e.g., lithium, uranium, rare earths) based on standardized codes.

# Load Ukraine map
ukraine_map <- st_read("gadm41_UKR_shp/gadm41_UKR_2.shp") %>%
  st_transform(crs = 4326)
## Reading layer `gadm41_UKR_2' from data source 
##   `C:\Users\Camilo Giraldo\Desktop\BSE - ITFD\2nd Term\Geospatial data science and economic spatial models\Final project\Final\gadm41_UKR_shp\gadm41_UKR_2.shp' 
##   using driver `ESRI Shapefile'
## Simple feature collection with 629 features and 13 fields
## Geometry type: MULTIPOLYGON
## Dimension:     XY
## Bounding box:  xmin: 22.14045 ymin: 44.38597 xmax: 40.21807 ymax: 52.37503
## Geodetic CRS:  WGS 84
# Load MRDS mineral deposit shapefile and transform to match CRS
mrds <- st_read("Minerals/mrds-trim.shp") %>%
  st_transform(crs = st_crs(ukraine_map))
## Reading layer `mrds-trim' from data source 
##   `C:\Users\Camilo Giraldo\Desktop\BSE - ITFD\2nd Term\Geospatial data science and economic spatial models\Final project\Final\Minerals\mrds-trim.shp' 
##   using driver `ESRI Shapefile'
## Simple feature collection with 304632 features and 5 fields
## Geometry type: POINT
## Dimension:     XY
## Bounding box:  xmin: -178.8205 ymin: -72.99718 xmax: 179.1318 ymax: 80.00096
## Geodetic CRS:  WGS 84
# Filter deposits located in Ukraine
mrds_ukraine <- st_filter(mrds, ukraine_map)

# Categorize mineral types
mrds_ukraine <- mrds_ukraine %>%
  mutate(mineral_group = case_when(
    grepl("LI", CODE_LIST, ignore.case = TRUE) ~ "Lithium",
    grepl("U", CODE_LIST, ignore.case = TRUE) ~ "Uranium",
    grepl("TI", CODE_LIST, ignore.case = TRUE) ~ "Titanium",
    grepl("ZR", CODE_LIST, ignore.case = TRUE) ~ "Zirconium",
    grepl("RE|RARE", CODE_LIST, ignore.case = TRUE) ~ "Rare Earths",
    grepl("MG|FE|MN", CODE_LIST, ignore.case = TRUE) ~ "Iron / Manganese",
    grepl("GRF|GRAPH", CODE_LIST, ignore.case = TRUE) ~ "Graphite",
    TRUE ~ "Other"
  ))

# Buffer zone
mrds_buffer <- st_transform(mrds_ukraine, crs = 3857) %>%
  st_buffer(dist = 80000) %>%
  st_transform(crs = 4326)
mrds_buffer$mineral_group <- mrds_ukraine$mineral_group

# Plot with Russian-controlled areas overlay
ggplot() +
  geom_sf(data = ukraine_map, fill = "gray95", color = "gray70", size = 0.3) +
  geom_sf(data = russian_control_2024, fill = "gray25", color = "gray25", alpha = 0.4) +
  geom_sf(data = mrds_buffer, aes(fill = mineral_group), alpha = 0.15, color = NA) +
  geom_sf(data = mrds_ukraine, aes(color = mineral_group), size = 2, alpha = 0.8) +
  scale_color_brewer(palette = "Set1", guide = guide_legend(title = NULL)) +
  scale_fill_brewer(palette = "Set1", guide = "none") +
  labs(
    title = "Mineral Deposits in Ukraine",
    subtitle = "Including Russian-controlled zones (shaded)",
    caption = "Source: USGS Mineral Resources Data System (2025)"
  ) +
  theme_minimal() +
  theme(
    legend.position = "bottom",
    plot.title = element_text(size = 16, hjust = 0.5, face = "bold"),
    plot.subtitle = element_text(size = 12, hjust = 0.5),
    plot.caption = element_text(size = 8, hjust = 1)
  )

Is more military aid sent to regions richer in strategic minerals?

To solve this question, we create a 50 km buffer around mineral sites, flags districts intersecting these zones, and joins them with fire and aid data. It then compares total aid received in areas near and far from minerals using a t-test to assess if the difference is statistically significant.

# Create unified mineral zone (buffered around deposits)
mineral_union <- mrds_ukraine %>%
  st_transform(crs = 3857) %>%
  st_buffer(50000) %>%
  st_union() %>%
  st_make_valid() %>%
  st_transform(crs = 4326)

# Flag districts that intersect mineral zones
ukraine_with_minerals <- ukraine_map %>%
  mutate(near_minerals = as.integer(st_intersects(geometry, mineral_union, sparse = FALSE)))

# Join fire data to tagged districts
fires_joined <- st_join(fires_by_area, ukraine_with_minerals, join = st_within, left = FALSE)

# Aggregate daily military aid to avoid many-to-many join
daily_aid <- UST_aid_type_general %>%
  group_by(announcement_date) %>%
  summarise(total_value_EUR = sum(total_value_EUR, na.rm = TRUE), .groups = "drop")

# Add aid info to fire data
fires_joined <- fires_joined %>%
  left_join(daily_aid, by = c("date" = "announcement_date"))

# Summarize aid by mineral proximity
mineral_aid <- fires_joined %>%
  group_by(near_minerals) %>%
  summarise(
    total_aid = sum(total_value_EUR, na.rm = TRUE),
    n_obs = n(),
    .groups = "drop"
  )

# Run t-test comparing aid near vs. not near minerals
aid_test <- t.test(total_value_EUR ~ near_minerals, data = fires_joined)

# Print output
print(mineral_aid)
## Simple feature collection with 2 features and 3 fields
## Geometry type: MULTIPOINT
## Dimension:     XY
## Bounding box:  xmin: 23.76881 ymin: 44.58154 xmax: 40.14915 ymax: 52.35956
## Geodetic CRS:  WGS 84
## # A tibble: 2 × 4
##   near_minerals total_aid  n_obs                                        geometry
##           <int>     <dbl>  <int>                                <MULTIPOINT [°]>
## 1             0   1.21e13  94900 ((28.55419 45.66073), (28.55521 45.66264), (28…
## 2             1   3.99e13 224903 ((33.95181 44.58154), (33.95803 44.58506), (33…
print(aid_test)
## 
##  Welch Two Sample t-test
## 
## data:  total_value_EUR by near_minerals
## t = -18.725, df = 120156, p-value < 2.2e-16
## alternative hypothesis: true difference in means between group 0 and group 1 is not equal to 0
## 95 percent confidence interval:
##  -64340191 -52147328
## sample estimates:
## mean in group 0 mean in group 1 
##       241329916       299573675

The two Sample t-test reveals a statistically significant difference in the average amount of military aid between regions near strategic minerals and those that are not (p-value < 2.2e-16). Specifically, areas located near mineral zones received, on average, approximately €299.6 million, compared to €241.3 million in other regions—a difference of over €58 million. This suggests that military aid allocations may be spatially correlated with the presence of valuable mineral resources, potentially reflecting strategic considerations in targeting support toward areas with higher economic or military relevance.

There is a strong positive relationship between cumulative military aid and the size of war-related fires occurring near strategic mineral deposits. In Russian-controlled areas, the correlation is high (r = 0.198), suggesting that as more aid is allocated, the intensity of conflict near mineral zones increases significantly, likely reflecting Ukraine’s offensive actions in these resource-rich areas. In Ukrainian-controlled territories, the correlation remains strong (r = 0.272), though slightly weaker, which may indicate a mix of defensive operations or Russian targeting of these zones. Overall, the findings support the idea that mineral-rich regions are more actively contested and closely linked to the flow of international military support.

5. Conclusions

We have investigated whether international military aid to Ukraine can be used as a proxy for delivered weapons by analyzing its correlation with war-related fire activity. Using a series of empirical tests, the results show a consistent and statistically significant positive relationship between cumulative military aid and the extent of war fire activity. However, 

In our first test, we assessed whether there is a general correlation between cumulative international military aid and war-related fire activity in Ukraine.  Our analysis revealed a moderate positive and statistically significant relationship, suggesting that increases in aid are associated with rising levels of war fire activity over time. Despite the time lag and uncertainty in actual weapons delivery, aid allocations do appear to correlate with battlefield intensity, offering some initial support for the use of aid as a proxy for delivered weapons.

In the second test, we separate fire activity in Russian- and Ukrainian-controlled areas. Contrary to the initial hypothesis that military aid would correlate more strongly with fires in Russian-held territories, the correlation was stronger in Ukrainian-controlled regions than in Russian-held ones. This could indicate that battlefield dynamics are more complex than what we assumed. This finding could be explained if international military aid also influences combat intensity within Ukraine’s own territory—possibly due to ongoing defense, counterattacks, or fighting in contested zones.

The third test explored logistical dynamics, showing that aid has a stronger correlation with fires occurring near major roads.  When disaggregated by territorial control, the analysis showed that this relationship holds in both Russian- and Ukrainian-controlled areas, but it is particularly pronounced in Russian-controlled regions. In other words, aid is more likely to correlate with increased fire activity in occupied territories that are logistically accessible—supporting the hypothesis that transport infrastructure facilitates the deployment of aid-supported operations, especially offensive ones. In this case, the findings do align with our theoretical expectations. 

Finally, we consider natural resources. In our fourth test, we explored the correlation between international military aid and  war fires close to the known strategic mineral sites. We expected to find a negative correlation between international military aid and fires near natural resources, as Ukrainian forces would avoid targeting valuable resources. We do not find evidence supporting this hypthothesis. A possible explanation for our findings is that Russian troops and military assets are located on these natural resources, and are therefore targeted by Ukraine using international military aid. 

Overall, our findings remain inconclusive. We do find some evidence to support the idea that military aid is at least partially realized as deployed weapons, and can therefore serve as a rough, but informative, proxy for measuring battlefield effects of foreign support. However, unexpected results in our second and fourth tests call for caution on the use of this data for the evaluation of military aid to Ukraine.

In both cases, our initial assumptions should be revisited. These unexpected patterns in the data could be explained with more complex battle dynamics, such as the defensive use of weapons in Ukrainian-controlled territory, and a more nuanced understanding of the placement of Russian military assets around strategic natural resources . 

6. References

Glanville, L., & Pattison, J. (2024). Ukraine and the opportunity costs of military aid. International Affairs, 100(4), 1571–1590. https://doi.org/10.1093/ia/iiae122

Tian, N., Lopes da Silva, D., Béraud-Sudreau, L., Liang, X., Scarazzato, L., & Assis, A. (2023). Developments in military expenditure and the effects of the war in Ukraine. Defence and Peace Economics, 34(5), 547–562. https://doi.org/10.1080/10242694.2023.2221877

World Bank. (2023). Ukraine - Roads. World Bank Data Catalog.Retrieved from https://datacatalog.worldbank.org/search/dataset/0061358/Ukraine---Roads

Trebesch, C., Antezza, A., Bushnell, K., Frank, A., Frank, P., Franz, L., Kharitonov, I., Kumar, B., Rebinskaya, E., & Schramm, S. (2023). The Ukraine Support Tracker. Kiel Working Paper No. 2218. Kiel Institute for the World Economy. Retrieved from https://www.ifw-kiel.de/topics/war-against-ukraine/ukraine-support-tracker/

The Times. (2024, March). American red tape is standing in the way of victory. Retrieved from https://www.thetimes.com/world/russia-ukraine-war/article/american-red-tape-standing-way-victory-weapons-ukraine-l2tjd2kg9?region=global

The Economist. (2022). War Fires Dataset (ukraine_war_fires.csv) [Data set]. GitHub. Retrieved from https://github.com/TheEconomist/the-economist-war-fire-model/tree/master/source-data

Harward, C., Evans, A., Mappes, G., Gibson, O., Novikov, D., & Barros, G. (2025, March 24). Russian Offensive Campaign Assessment, March 24, 2025. Institute for the Study of War. Retrieved from https://www.understandingwar.org/backgrounder/russian-offensive-campaign-assessment-march-24-2025